/*
 * iSistemaBUS.cpp
 *
 *  Created on: 13/07/2014
 *      Author: migue
 */

#include "iSistemaBUS.h"
#include <sstream>
#include <signal.h>
#include <syslog.h>
#include <string.h>
#include <stdio.h>
#include "../comun/ServidorIDs.h"
#include "../comun/ServidorRemoto.h"
#include <unistd.h>

iSistemaBUS::iSistemaBUS() :_cEnvio(RUTA, COLASISTEMA), _cRecibo(RUTA, COLARECIBO_CLI)
{
	_CCLanzado = false;
	_idBusRepuesto = 0;
	_idRepuestoBusGeneral = 0;
	_numBusRoto = 0;
	_pidE = 0;
	_pidR = 0;
	_idBroker = 0;

	_idBusRoto = -1;
}

iSistemaBUS::~iSistemaBUS() {
	if (_CCLanzado) {
		ServidorRemoto serv;
		serv.consultarDatos(_idBusRepuesto);

		// envio mensaje de finalizacion

		MENSAJE msj;
		msj.destinatario = _idBusRepuesto;
		msj.destinatarioFinal = serv.idBrokerConectado();
		msj.origen = _idBusRepuesto;

		msj.tipo = Tipos::MSJ_NORMAL;
		msj._ipc.op_ipc = TIPO_FINALIZAR;

		_cEnvio.enviar(&msj, TAM_MENSAJE);

		if (_idBusRoto != serv.pedirIdBUSRepuesto(_numBusRoto, _idBusRepuesto) ){
			perror("ERROR se esperaba id real de bus de repuesto reemplzado");
		}
	}

}

void iSistemaBUS::informarEsperaABroker() {
	MENSAJE msj;

	msj.tipo = Tipos::MSJ_ANUNCIAR_BUS_REPUESTO;

	msj.destinatario = _idBusRepuesto;
	msj.destinatarioFinal = _idBroker;
	msj.origen = _idBusRepuesto;

	msj.id = _idBusRepuesto;

	_cEnvio.enviar(&msj, TAM_MENSAJE);

}

int iSistemaBUS::esperarPedidoDeRepuesto(Tipos::LugarDeSala& destino) {
	ServidorRemoto serv;
	int numBusRoto;

	_idBusRepuesto = serv.pedirIdBUSRepuestoGeneral(_idRepuestoBusGeneral);
	_idBroker = serv.idBrokerConectado();

	// Lanzando Corte de Colas
	lanzarCorteDeColas(_idBusRepuesto);

	informarEsperaABroker();

	MENSAJE msj;

	//_colaSistema.recibir((void*) &msj, TAM_MENSAJE, serv.idBUSRepuestoGeneral());
	//_cRecibo.recibir((void*) &msj, TAM_MENSAJE, _idRepuestoBusGeneral);
	syslog(LOG_INFO, "BUS REPUESTO, esperado en cola por peticion con id: %i", _idBusRepuesto);

	//_cRecibo.recibir((void*) &msj, TAM_MENSAJE, _idBusRepuesto);
	_cRecibo.recibirMensaje(msj, Tipos::MSJ_PEDIDO_BUS_REPUESTO, _idBusRepuesto);

	syslog(LOG_INFO, "BUS REPUESTO id: %i; Recibida peticion para REPONER", _idBusRepuesto);


	destino = msj.lugar;
	numBusRoto = msj.id;

	if (msj.tipo != Tipos::MSJ_PEDIDO_BUS_REPUESTO) {
		syslog(LOG_INFO, "TIPO INCORRECTO en iSistemaBUS::esperarPedidoDeRepuesto(), esperado: %i, llego: %i; origen: %li, destino: %li, destFinal: %li",
				(int) Tipos::MSJ_PEDIDO_BUS_REPUESTO, (int) msj.tipo, msj.origen, msj.destinatario, msj.destinatarioFinal);
	}
	else {
		syslog(LOG_INFO, "Recibido Pedido de Reemplazo de Bus %i ROTO", numBusRoto);
	}


	_numBusRoto = numBusRoto;
	return numBusRoto;
}

/**
 * retorna el id de la persona subida,
 * 0 si no hay mas personas.
 */
int iSistemaBUS::esperarSubidaDePersona(int numBusRoto) {

	ServidorRemoto serv;
	int idPersona;
	int idBusReemplazo = _idBusRepuesto;
	//int idBusRoto = serv.consultarIdBus(_numBusRoto);
	_idBusRoto = serv.consultarIdBus(_numBusRoto);

	MENSAJE msj;


	msj.destinatario = idBusReemplazo;
	msj.destinatarioFinal = _idBusRoto;
	msj.origen = idBusReemplazo;
	msj.id = idBusReemplazo;
	msj.tipo = Tipos::MSJ_PETICION_CAMBIO_DE_BUS;



	// envio peticion a bus roto para subir pasajero
	//_colaSistema.enviar((void*) &msj, TAM_MENSAJE);
	_cEnvio.enviar((void*) &msj, TAM_MENSAJE);

	//espero respuesta de bus roto para subir pasajero
	//_colaSistema.recibir((void*) &msj, TAM_MENSAJE, idBusReemplazo);
	//_cRecibo.recibir((void*) &msj, TAM_MENSAJE, idBusReemplazo);
	_cRecibo.recibirMensaje(msj, Tipos::MSJ_NORMAL, idBusReemplazo);

	if (msj.tipo != Tipos::MSJ_NORMAL) {
		syslog(LOG_INFO," Error de tipo en iSistemaBUS::esperarSubidaDePersona(), esperado: %i, llego: %i; origen: %li, destino: %li, destFinal: %li",
							(int) Tipos::MSJ_NORMAL, (int) msj.tipo, msj.origen, msj.destinatario, msj.destinatarioFinal);
	}

	// si envia con id == 0 es que ya no hay mas pasajeros
	if (msj.id != 0) {
		idPersona = msj.id;


		msj.destinatario = idBusReemplazo;
		msj.destinatarioFinal = idPersona;
		msj.origen = idBusReemplazo;
		msj.tipo = Tipos::MSJ_BUS_ROTO;
		msj.id = idBusReemplazo;


		// envio msj a persona indicando que Bus esta roto y que suba al de reemplazo
		//_colaSistema.enviar((void*) &msj, TAM_MENSAJE);
		_cEnvio.enviar((void*) &msj, TAM_MENSAJE);

		// espero que persona suba al bus de reemplazo
		//_colaSistema.recibir((void*) &msj, TAM_MENSAJE, idBusReemplazo);
		//_cRecibo.recibir((void*) &msj, TAM_MENSAJE, idBusReemplazo);
		_cRecibo.recibirMensaje(msj, Tipos::MSJ_CONFIRMAR_SUBIDA_A_BUS, idBusReemplazo);

		if (msj.tipo != Tipos::MSJ_CONFIRMAR_SUBIDA_A_BUS) {
			syslog(LOG_INFO," Error de tipo en iSistemaBUS::esperarSubidaDePersona(), esperado: %i, llego: %i; origen: %li, destino: %li, destFinal: %li",
					(int) Tipos::MSJ_CONFIRMAR_SUBIDA_A_BUS, (int) msj.tipo, msj.origen, msj.destinatario, msj.destinatarioFinal);
		}

		return idPersona;
	}
	else {
		return 0;
	}
}



/**************************************************************************
 *  Metodos para el BUS roto
 **************************************************************************/
void iSistemaBUS::peticionDeBusDeRepuesto(int numBusRoto, Tipos::LugarDeSala lugarDestino) {
//	ServidorIDs serv;
//	int idPedidoBUS = serv.idBUSRepuestoGeneral();

	ServidorRemoto serv;
	//int idPedidoBUS = serv.idBusRepuestoGeneral();
	//int idBUS_repuesto = serv.pedirIdBUSRepuestoGeneral(idPedidoBUS);

	MENSAJE msj;

	_idBusRoto = serv.consultarIdBus(numBusRoto);
	int idBroker = serv.idBrokerConectado();

	//msj.destinatario = idPedidoBUS;
	msj.destinatario = _idBusRoto;
	msj.origen = _idBusRoto;
	msj.destinatarioFinal = idBroker;
	msj.lugar = lugarDestino;

	msj.id = numBusRoto;
	msj.tipo = Tipos::MSJ_PEDIDO_BUS_REPUESTO;

	//_colaSistema.enviar((void*) &msj, TAM_MENSAJE);
	_cEnvio.enviar((void*) &msj, TAM_MENSAJE);

	syslog(LOG_INFO, "Enviada peticion de Reemplazo de Bus %i Roto", numBusRoto);
}

void iSistemaBUS::esperarPeticionYEnviarPersona(int idPersona, int numBusRoto) {
//	ServidorIDs serv;
//	int idBusRoto = serv.idBUS(numBusRoto);

	_numBusRoto = numBusRoto;

	//ServidorRemoto serv;
	//int idBusRoto = serv.consultarIdBus(numBusRoto);

	MENSAJE msj;

	//_cRecibo.recibir((void*) &msj, TAM_MENSAJE , _idBusRoto);
	_cRecibo.recibirMensaje(msj, Tipos::MSJ_PETICION_CAMBIO_DE_BUS , _idBusRoto);

	int idBusRepuesto = msj.origen;

	syslog(LOG_INFO, "Recibida peticion para subir persona al bus de reemplazo con id: %i", idBusRepuesto);


	if (msj.tipo == Tipos::MSJ_PETICION_CAMBIO_DE_BUS) {

//		msj.destinatario = idBusRepuesto; // serv.idBUSRepuesto(numBusRoto);
//		msj.origen = _idBusRoto;
//		msj.id = idPersona;


		msj.destinatario = _idBusRoto;
		msj.destinatarioFinal = idBusRepuesto; // serv.idBUSRepuesto(numBusRoto);
		msj.origen = _idBusRoto;
		msj.id = idPersona;



		msj.tipo = Tipos::MSJ_NORMAL;

		//_colaSistema.enviar((void*) &msj, TAM_MENSAJE);
		_cEnvio.enviar((void*) &msj, TAM_MENSAJE);

		syslog(LOG_INFO, "Enviando idPersona: %i, para subir a bus de Reemplazo con id: %i", idPersona, idBusRepuesto);//serv.idBUSRepuesto(numBusRoto));
	}
	else {
		syslog(LOG_INFO, "TIPO INCORRECTO en iSistemaBUS::esperarPeticionYEnviarPersona(), esperado: %i, llego: %i; origen: %li, destino: %li, destFinal: %li",
				(int)Tipos::MSJ_PETICION_CAMBIO_DE_BUS, (int)msj.tipo, msj.origen, msj.destinatario, msj.destinatarioFinal);
		perror("Mensaje de peticion de cambio de pasajero (Bus a Bus) llego mal.");
	}
}




void iSistemaBUS::lanzarCorteDeColas(int id) {
	_CCLanzado = true;

	std::stringstream idAux;
	idAux << id;
	int pid = fork();
	if (pid == 0) {
		execlp("./conexBrokerCliente", "conexBrokerCliente",
				idAux.str().c_str(), "E", NULL);
		perror("Error en el exec conexionBrokerCliente");
		exit(1);
	}
	pid = fork();
	if (pid == 0) {
		execlp("./conexBrokerCliente", "conexBrokerCliente",
				idAux.str().c_str(), "R", NULL);
		perror("Error en el exec conexionBrokerCliente");
		exit(1);
	}

}
